package com.tmc.util;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.BigDecimalConverter;
import org.apache.commons.beanutils.converters.DoubleConverter;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.beanutils.converters.LongConverter;
import org.apache.commons.beanutils.converters.ShortConverter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tmc.bean.common.ContextInfo;
import com.tmc.bean.common.Pagination;
import com.tmc.entity.common.BaseEntity;

public class ObjectUtil {

	private static Log logger = LogFactory.getLog(ObjectUtil.class);

	/** bean嵌套 */
	private static final String NESTED = ".";

	public static <T> T makeTargetBean(Object obj, Class<T> clazz) {
		String json = JSON.toJSONString(obj);
		return (T) JSON.parseObject(json, clazz);
	}
	
	public static <T> List<T> makeTargetList(List<?> list, Class<T> clazz) {
		if (list == null || list.isEmpty()) {
			return null;
		}
		List<T> result = new ArrayList<T>();
		for (Object obj : list) {
			T bean = makeTargetBean(obj, clazz);
			result.add(bean);
		}
		return result;
	}

	public static <T> List<T> mapToList(Map<String, T> map) {
		List<T> list = new ArrayList<T>();
		for (String key : map.keySet()) {
			list.add(map.get(key));
		}
		return list;
	}
	
	public static <T> List<T> mapToList1(Map<String, List<T>> map) {
		List<T> list = new ArrayList<T>();
		for (String key : map.keySet()) {
			list.addAll(map.get(key));
		}
		return list;
	}
	
	public static <T> LinkedHashMap<String, T> combileMap(LinkedHashMap<String, T> map1, LinkedHashMap<String, T> map2){
		if (map1 == null || map1.isEmpty()){
			return map2;
		}
		if (map2 == null || map2.isEmpty()){
			return map1;
		}
		for (String key : map2.keySet()){
			map1.put(key, map2.get(key));
		}
		return map1;
	}

	public static <T> List<T> newList(T obj) {
		List<T> list = new ArrayList<T>();
		list.add(obj);
		return list;

	}

	public static boolean hasText(String textValue) {
		return textValue != null && !"".equals(textValue);
	}

	public static boolean noText(String textValue) {
		return !hasText(textValue);
	}
	
	public static <T> boolean noItems(Pagination<T> page){
		if (page == null || page.getItems() == null || page.getItems().isEmpty()){
			return true;
		}
		return false;
	}
	
	public static boolean inArray(String theStr, String[] strs){
		if (strs == null || strs.length < 1 || noText(theStr)){
			return false;
		}
		theStr = theStr.trim();
		for (String str : strs){
			if (theStr.equals(str)){
				return true;
			}
		}
		return false;
	}

	public static String toUpperCase(String str) {
		if (noText(str)) {
			return str;
		}
		return str.toUpperCase();
	}

	public static String toUpAndSlash(String str) {
		String result = toUpperCase(str);
		if (noText(result)) {
			return result;
		}
		if (!result.endsWith("/")) {
			result += "/";
		}
		return result;
	}

	public static String toLowerCase(String str) {
		if (noText(str)) {
			return str;
		}
		return str.toLowerCase();
	}

	public static void setBaseInfo(BaseEntity entity, ContextInfo context) {
		if (entity.getCreationDate() == null) {
			entity.setCreationDate(DateUtil.toLongDate(new Date()));
		}
		if (entity.getLastUpdateDate() == null) {
			entity.setLastUpdateDate(DateUtil.toLongDate(new Date()));
		}
		if (context == null){
			entity.setCreatedBy(-1L);
			entity.setLastUpdatedBy(-1L);
		} else {
			entity.setCreatedBy(context.getUserId());
			entity.setLastUpdatedBy(context.getUserId());
		}
		entity.setEnabledFlag("Y");
	}

	public static void updateBaseInfo(BaseEntity entity, ContextInfo context) {
		entity.setLastUpdateDate(DateUtil.toLongDate(new Date()));
		if (context == null){
			entity.setLastUpdatedBy(-1L);
		} else {
			entity.setLastUpdatedBy(context.getUserId());
		}
	}

	public static final void copyIncludeProperties(final Object source, Object dest, final String[] includeProperties)
			throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException,
			IntrospectionException {
		if (includeProperties == null || includeProperties.length == 0) {
			throw new IllegalArgumentException("未传入要拷贝的属性列表");
		}
		if (source == null) {
			throw new IllegalArgumentException("要拷贝的源对象为空");
		}
		if (dest == null) {
			throw new IllegalArgumentException("要拷贝的目的对象为空");
		}
		// 日志信息
		if (logger.isTraceEnabled()) {
			logger.trace("[source bean: " + source.getClass().getName() + " ]");
			logger.trace("[destination bean: " + dest.getClass().getName() + " ]");
		}
		// 拷贝
		for (String property : includeProperties) {
			PropertyDescriptor sourcePropertyDescriptor = null;
			PropertyDescriptor destPropertyDescriptor = null;
			if (isSimpleProperty(property)) { // 简单属性
				sourcePropertyDescriptor = getProperty(property, source);
				destPropertyDescriptor = getProperty(property, dest);
				if (sourcePropertyDescriptor == null) {
					throw new IllegalArgumentException("要拷贝的源对象不存在该属性");
				}
				if (destPropertyDescriptor == null) {
					throw new IllegalArgumentException("要拷贝到的目标对象不存在该属性");
				}
				copyProperty(property, source, dest);
			} else { // 嵌套bean属性
				Object target = dest;
				Object realSource = source;
				String[] nestedProperty = getNestedProperty(property);
				if (nestedProperty != null && nestedProperty.length > 1) {
					for (int i = 0; i < nestedProperty.length - 1; i++) {
						sourcePropertyDescriptor = getProperty(nestedProperty[i], realSource);
						destPropertyDescriptor = getProperty(nestedProperty[i], target);
						if (sourcePropertyDescriptor == null) {
							throw new IllegalArgumentException("要拷贝的源对象不存在该属性");
						}
						if (destPropertyDescriptor == null) {
							throw new IllegalArgumentException("要拷贝到的目标对象不存在该属性");
						}
						Method readMethod = sourcePropertyDescriptor.getReadMethod();
						realSource = readMethod.invoke(realSource);
						readMethod = destPropertyDescriptor.getReadMethod();
						Method writeMethod = destPropertyDescriptor.getWriteMethod();
						Object value = readMethod.invoke(target);
						if (value == null) {
							value = destPropertyDescriptor.getPropertyType().newInstance();
							writeMethod.invoke(target, value);
						}
						target = value;
					}
					final String prop = nestedProperty[nestedProperty.length - 1];
					sourcePropertyDescriptor = getProperty(prop, realSource);
					destPropertyDescriptor = getProperty(prop, target);
					if (sourcePropertyDescriptor == null) {
						throw new IllegalArgumentException("要拷贝的源对象不存在该属性");
					}
					if (destPropertyDescriptor == null) {
						throw new IllegalArgumentException("要拷贝到的目标对象不存在该属性");
					}
					copyProperty(prop, realSource, target);
				}
			}
		}
	}
	/**
	 * 解决非包装类的默认值问题
	 */
	static {
		ConvertUtils.register(new LongConverter(null), Long.class);
		ConvertUtils.register(new ShortConverter(null), Short.class);
		ConvertUtils.register(new IntegerConverter(null), Integer.class);
		ConvertUtils.register(new DoubleConverter(null), Double.class);
		ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class);
	}

	/**
	 * 复制bean的属性（支持嵌套属性，以点号分割）
	 * 
	 * @param source
	 *            拷贝属性的源对象
	 * 
	 * @param dest
	 *            拷贝属性的目的地对象
	 * 
	 * @param includeProperties
	 *            拷贝的属性列表
	 * 
	 * 
	 * @throws IntrospectionException
	 * 
	 * @throws InvocationTargetException
	 * 
	 * @throws IllegalAccessException
	 * 
	 * @throws IllegalArgumentException
	 * 
	 * @throws InstantiationException
	 * 
	 * @throws ClassNotFoundException
	 * 
	 * @throws IOException
	 * 
	 * @date 2013-12-18
	 */
	public static void copyProperties(final Object source, final Object dest, final String... excludeProperties)
			throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException,
			InstantiationException, IOException, ClassNotFoundException {
		final Object backupSource = clone(dest);
		if (source == null) {
			throw new IllegalArgumentException("要拷贝的源对象为空");
		}
		if (dest == null) {
			throw new IllegalArgumentException("要拷贝的目的对象为空");
		}
		org.apache.commons.beanutils.BeanUtils.copyProperties(dest, source);
		// 还原排除的属性值
		revertProperties(backupSource, dest, excludeProperties);
	}

	/**
	 * 从备份对象中还原属性
	 * 
	 * @param backup
	 *            备份bean
	 * 
	 * @param target
	 *            目标bean
	 * 
	 * @param properties
	 *            属性列表
	 * 
	 * @author yang_qiao
	 * 
	 * @throws InvocationTargetException
	 * 
	 * @throws IllegalAccessException
	 * 
	 * @throws IllegalArgumentException
	 * 
	 * @throws IntrospectionException
	 * 
	 * @throws InstantiationException
	 * 
	 * @date 2013-12-18
	 */
	private static void revertProperties(final Object backup, Object target, final String... properties)
			throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, IntrospectionException,
			InstantiationException {
		if (properties == null || properties.length == 0) {
			return;
		}
		if (backup == null) {
			throw new IllegalArgumentException("备份对象为空");
		}
		if (target == null) {
			throw new IllegalArgumentException("目的对象为空");
		}
		// 日志信息
		if (logger.isTraceEnabled()) {
			logger.trace("[source bean: " + backup.getClass().getName() + " ]");
			logger.trace("[destination bean: " + target.getClass().getName() + " ]");
		}
		// 拷贝
		for (String property : properties) {
			PropertyDescriptor sourcePropertyDescriptor = null;
			PropertyDescriptor destPropertyDescriptor = null;
			if (isSimpleProperty(property)) { // 简单属性
				sourcePropertyDescriptor = getProperty(property, backup);
				destPropertyDescriptor = getProperty(property, target);
				if (sourcePropertyDescriptor == null) {
					throw new IllegalArgumentException("要拷贝的源对象不存在该属性");
				}
				if (destPropertyDescriptor == null) {
					throw new IllegalArgumentException("要拷贝到的目标对象不存在该属性");
				}
				copyProperty(property, backup, target);
			} else { // 嵌套bean属性
				Object targetObj = target;
				Object realBackup = backup;
				String[] nestedProperty = getNestedProperty(property);
				if (nestedProperty != null && nestedProperty.length > 1) {
					for (int i = 0; i < nestedProperty.length - 1; i++) {
						sourcePropertyDescriptor = getProperty(nestedProperty[i], realBackup);
						destPropertyDescriptor = getProperty(nestedProperty[i], targetObj);
						if (sourcePropertyDescriptor == null) {
							throw new IllegalArgumentException("要拷贝的源对象不存在该属性");
						}
						if (destPropertyDescriptor == null) {
							throw new IllegalArgumentException("要拷贝到的目标对象不存在该属性");
						}
						Method readMethod = sourcePropertyDescriptor.getReadMethod();
						realBackup = readMethod.invoke(realBackup);
						if (realBackup == null) { // 判断备份对象嵌套属性是否为空
							realBackup = sourcePropertyDescriptor.getPropertyType().newInstance();
						}
						Method writeMethod = destPropertyDescriptor.getWriteMethod();
						readMethod = destPropertyDescriptor.getReadMethod();
						Object value = readMethod.invoke(targetObj);
						if (value == null) {
							value = destPropertyDescriptor.getPropertyType().newInstance();
							writeMethod.invoke(targetObj, value);
						}
						targetObj = value;
					}
					final String prop = nestedProperty[nestedProperty.length - 1];
					sourcePropertyDescriptor = getProperty(prop, realBackup);
					destPropertyDescriptor = getProperty(prop, targetObj);
					if (sourcePropertyDescriptor == null) {
						throw new IllegalArgumentException("要拷贝的源对象不存在该属性");
					}
					if (destPropertyDescriptor == null) {
						throw new IllegalArgumentException("要拷贝到的目标对象不存在该属性");
					}
					copyProperty(prop, realBackup, targetObj);
				}
			}
		}
	}

	/**
	 * 对象克隆
	 * 
	 * @author yang_qiao
	 * 
	 * @date 2013-12-18
	 */
	private static Object clone(final Object value) throws IOException, ClassNotFoundException {
		// 字节数组输出流，暂存到内存中
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		// 序列化
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(value);
		ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bis);
		// 反序列化
		return ois.readObject();
	}

	/**
	 * 判断是否为简单属性，是，返回ture
	 * 
	 * @author yang_qiao
	 * 
	 * @date 2013-12-18
	 */
	private static boolean isSimpleProperty(final String property) {
		return !property.contains(NESTED);
	}

	/**
	 * 获取目标bean的属性
	 * 
	 * @author yang_qiao
	 * 
	 * @date 2013-12-17
	 */
	private static PropertyDescriptor getProperty(final String propertyName, final Object target) {
		if (target == null) {
			new IllegalArgumentException("查询属性的对象为空");
		}
		if (propertyName == null || "".equals(propertyName)) {
			new IllegalArgumentException("查询属性不能为空值");
		}
		PropertyDescriptor propertyDescriptor = null;
		try {
			propertyDescriptor = new PropertyDescriptor(propertyName, target.getClass());
		} catch (IntrospectionException e) {
			logger.info("不存在该属性");
			return null;
		}
		return propertyDescriptor;
	}

	/**
	 * 单个属性复制--原数据源和目的数据源必须要有该属性方可
	 * 
	 * @author yang_qiao
	 * 
	 * @throws InvocationTargetException
	 * 
	 * @throws IllegalAccessException
	 * 
	 * @throws IllegalArgumentException
	 * 
	 * @throws IntrospectionException
	 * 
	 * @date 2013-12-17
	 */
	public static void copyProperty(final String propertyName, final Object source, Object dest)
			throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, IntrospectionException {
		PropertyDescriptor property;
		property = new PropertyDescriptor(propertyName, source.getClass());
		Method getMethod = property.getReadMethod();
		Object value = getMethod.invoke(source);
		property = new PropertyDescriptor(propertyName, dest.getClass());
		Method setMethod = property.getWriteMethod();
		setMethod.invoke(dest, value);
	}

	/**
	 * 获取嵌套Bean的属性
	 * 
	 * @author yang_qiao
	 * 
	 * @date 2013-12-18
	 */
	public static String[] getNestedProperty(final String nestedProperty) {
		if (nestedProperty == null || "".equals(nestedProperty)) {
			new IllegalArgumentException("参数为空值");
		}
		return nestedProperty.split("\\" + NESTED);
	}
	
	public static Integer getIntegerValue(String str){
		if (noText(str)){
			return null;
		}
		return Integer.valueOf(str);
	}
	
	/**
	 * double数据保留两位小数
	 * @param f
	 * @return
	 */
	public static double getDouble2Decimal (double f){
		BigDecimal b = new BigDecimal(f+"");
		double f1 = b.setScale(2, BigDecimal.ROUND_CEILING).doubleValue();
		return f1;
	}
	/**
	 * double数据向上取整
	 * @param f
	 * @return
	 */
	public static double getDouble1Decimal (double f){
		BigDecimal b = new BigDecimal(f+"");
		double f1 = b.setScale(0, BigDecimal.ROUND_CEILING).doubleValue();
		return f1;
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static <T> Pagination<T> parsePage(String json, Class<T> clazz){
		JSONObject obj = JSON.parseObject(json);
		long  pageIndex = obj.getLongValue("pageIndex");
		long  pageSize = obj.getLongValue("pageSize");
		long  rowsCount = obj.getLongValue("rowsCount");
		String items = obj.getString("items");
		Pagination pagination = new Pagination(pageIndex, pageSize, rowsCount);
		List<T> list = new ArrayList<T>();
        if (items != null && !"".equals(items)) {
			JSONArray array = JSON.parseArray(items);
			if (array != null && array.size() > 0) {
				for (int i=0;i<array.size();i++) {
					T one = makeTargetBean(array.get(i), clazz);
					list.add(one);
				}
			}
		}
		pagination.setItems(list);
		return pagination;
	}
	
	public static Map<String, String> toMap(Object obj) {
		Map<String, String> map = new HashMap<String, String>();
		JSONObject json = JSONObject.parseObject(JSON.toJSONString(obj));
		for (Entry<String, Object> entry : json.entrySet()) {
			map.put(entry.getKey(), entry.getValue() + "");
		}
		return map;
	}
}
